﻿#include "TlvLogTextArea.h"
#include "ui_TlvLogTextArea.h"
#include "services/tlv/Com/TlvThreadCom.h"
#include "services/Task/TlvCodeTask.h"
#include "services/tlv/Base/iic.h"
#include "components/Toast/Toast.h"
#include "utils/Time/Time.h"
#include "stores/DataStroes.h"

#include <QScrollBar>
#include <QFileDialog>

TlvLogTextArea::TlvLogTextArea(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::TlvLogTextArea)
    , m_enAS(true)
{
    ui->setupUi(this);
    int maxline = DataStroes::instance()->settings()->model().data().log.maxline;
    setMaxLineCount(maxline);  // 最多显示9001行，避免内存爆满

    connect(TlvThreadCom::instance(), &TlvThreadCom::dataReceived, this, &TlvLogTextArea::onTlvDataReceived);
    connect(TlvThreadCom::instance(), &TlvThreadCom::dataSend, this, &TlvLogTextArea::onTlvDataSend);
    connect(TlvThreadCom::instance(), &TlvThreadCom::errorOccurred, this, &TlvLogTextArea::onTlvErrorOccurred);

    connect(TlvCodeTask::instance(), &TlvCodeTask::hasLog, this, &TlvLogTextArea::logText);
    connect(TlvCodeTask::instance(), &TlvCodeTask::errorOccurred, this, &TlvLogTextArea::logError);
}

TlvLogTextArea::~TlvLogTextArea()
{
    delete ui;
}

void TlvLogTextArea::logText(const QString &text)
{
    customLog(text, Qt::black);
}

void TlvLogTextArea::logError(const QString &err)
{
    customLog(err, Qt::red);
}

void TlvLogTextArea::logTlv(const Tlv& tlv)
{
    bool canLog = false;
    // filter
    const QList<TlvTag>& filters = DataStroes::instance()->settings()->model().data().log.tag_filter;
    for (const TlvTag& tag : filters) {
        if (tag == tlv.tag()) {
            canLog = true;
            break;
        }
    }
    if (!canLog) return;

    QString log;
    if (tlv.isIicFeedback() || tlv.isIicCall()) {
        IIC iic = IIC::fromTlv(tlv);
        log = iic.toLog();
    } else {
        log = tlv.toLog();
    }
    logText(
        QString("[%1]\n%2").arg(Time::getTimeString()).arg(log)
    );
}

void TlvLogTextArea::setMaxLineCount(int count)
{
    // 太影响性能，所以请用户手动清空日志
    // ui->teLog->document()->setMaximumBlockCount(count);
    Q_UNUSED(count);
}

int TlvLogTextArea::maxLineCount() const
{
    return ((int)(1) << (sizeof(int) - 1)) - 1;
    // return ui->teLog->document()->maximumBlockCount();
}

void TlvLogTextArea::setAutoScrolling(bool en)
{
    m_enAS = en;
}

void TlvLogTextArea::customLog(const QString &text, const QColor &textColor)
{
    QString color = textColor.name(QColor::HexRgb);
    QString replace = QString(text)
                          .toHtmlEscaped();       // 避免用户文本中有 < > 造成HTML错乱
    QString html = QString("<p style=\"color:%1;white-space: pre;\">%2</p><br>")
                       .arg(color)
                       .arg(replace);

    if (m_enAS) {
        // 自动滚动时，直接插入并移动到末尾
        ui->teLog->insertHtml(html);
        ui->teLog->moveCursor(QTextCursor::End);
    } else {
        // 不自动滚动时，保持当前滚动位置不变
        QScrollBar *vScrollBar = ui->teLog->verticalScrollBar();
        int curPos = vScrollBar->value();
        ui->teLog->insertHtml(html);
        vScrollBar->setValue(curPos);
    }
}

void TlvLogTextArea::onTlvErrorOccurred(const QString &msg)
{
    Toast::error(msg);
}

void TlvLogTextArea::onTlvDataSend(const Tlv &tlv)
{
    logTlv(tlv);
}

void TlvLogTextArea::onTlvDataReceived(const Tlv &tlv)
{
    logTlv(tlv);
}

void TlvLogTextArea::on_btnAutoScrolling_clicked()
{
    if (m_enAS) {
        ui->btnAutoScrolling->setIcon(QIcon(":/imgs/play.png"));
    } else {
        ui->btnAutoScrolling->setIcon(QIcon(":/imgs/pause.png"));
    }
    setAutoScrolling(!m_enAS);
}


void TlvLogTextArea::on_btnExport_clicked()
{
    QString log = ui->teLog->toPlainText();
    if (log.isEmpty()) {
        Toast::warning(tr("No log to export!"));
        return;
    }
    QString filename = QString("%1/TlvLog_%2.txt").arg(QDir::homePath()).arg(Time::getTimeString2());
    QString filePath = QFileDialog::getSaveFileName(this, tr("Export log to file"), filename, tr("Text File (*.txt)"));
    if (filePath.isEmpty()) return;
    QFile fp(filePath);
    if (!fp.open(QIODevice::WriteOnly)) {
        Toast::error(tr("Log file write failed!"));
        return;
    }
    fp.write(log.toUtf8());
    fp.close();
    Toast::success(tr("Export Successfully: ") + filePath);
}


void TlvLogTextArea::on_btnClear_clicked()
{
    ui->teLog->clear();
}

